//
// Created by chizuru on 2025/9/2.
//

#include "CLBProtocolCodec.h"
using std::vector;

std::string CLBProtocolCodec::parseUint32ToString(uint32_t value) {
    char buf[5]{};
    buf[0] = static_cast<char>((value >> 24) & 0xFF);
    buf[1] = static_cast<char>((value >> 16) & 0xFF);
    buf[2] = static_cast<char>((value >> 8) & 0xFF);
    buf[3] = static_cast<char>(value & 0xFF);
    buf[4] = 0;

    return std::string(buf);
}

vector<uint8_t>
CLBProtocolCodec::buildWriteFrame(const CommandId &addr, const IProtocolCodec::CodecArgs &args) const {
    // numeric (register) style
    if (auto pid = std::get_if<uint16_t>(&addr.v)) {
        uint16_t addr = *pid;
        uint32_t value = get<uint32_t>(args[0]);
        std::vector<uint8_t> f(7);
        f[0] = 0x57;
        f[1] = static_cast<uint8_t>((addr >> 8) & 0xFF);
        f[2] = static_cast<uint8_t>(addr & 0xFF);
        f[3] = static_cast<uint8_t>((value >> 24) & 0xFF);
        f[4] = static_cast<uint8_t>((value >> 16) & 0xFF);
        f[5] = static_cast<uint8_t>((value >> 8) & 0xFF);
        f[6] = static_cast<uint8_t>((value) & 0xFF);
        return f;
    }

    return {}; // unsupported combination -> empty frame (caller should handle)
}

vector<uint8_t>
CLBProtocolCodec::buildReadFrame(const CommandId &addr, const IProtocolCodec::CodecArgs &args) const {
    if (auto pid = std::get_if<uint16_t>(&addr.v)) {
        uint16_t addr = *pid;
        return std::vector<uint8_t>{0x52, static_cast<uint8_t>((addr >> 8) & 0xFF), static_cast<uint8_t>(addr & 0xFF)};
    }
    return {};
}

ProtocolResult CLBProtocolCodec::parseWriteResponse(std::span<const uint8_t> resp, const CommandId &commandId, const CodecArgs& args) const {
    if (resp.size() == 0) return ProtocolResult::Fail(0x02);
    if (resp.size() == 1 && resp[0] == 0x06)
        return ProtocolResult::Ok({}, std::vector<uint8_t>(resp.begin(), resp.end()));
    if (resp.size() == 2 && resp[0] == 0x15)
        return ProtocolResult::Fail(resp[1]);
    return ProtocolResult::Fail(0x01);
}

ProtocolResult CLBProtocolCodec::parseReadResponse(std::span<const uint8_t> resp, const CommandId &commandId, const CodecArgs& args) const {
    if (resp.size() == 0) return ProtocolResult::Fail(0x02);
    if (resp.size() == 5 && resp[0] == 0x06) {
        uint32_t v = (static_cast<uint8_t>(resp[1])<<24) | (static_cast<uint8_t>(resp[2])<<16)
                     | (static_cast<uint8_t>(resp[3])<<8) | static_cast<uint8_t>(resp[4]);
        ProtocolResult::CodecArg arg = static_cast<uint32_t>(v);
        return ProtocolResult::Ok({arg}, std::vector<uint8_t>(resp.begin(), resp.end()));
    }
    if (resp.size() == 2 && resp[0] == 0x15) return ProtocolResult::Fail(static_cast<uint8_t>(resp[1]));
    return ProtocolResult::Fail(0x01);
}
